﻿Module Main

    ' SELF EXTRACTING IMAGE FORMAT
    '   ArpsEngine.dll and HGLEngine.dll are packed automatically inside this executable at compilation time
    '   using PostCompilation VS2010 events or (optionally) running PackDlls.cmd on release directory
    '
    ' Executable Image Structure
    '
    '     StandAloneArphoonPackage.exe
    '        + HGLEngine.dll at position X1 (OBSOLETE)
    '        + ArpsEngine.dll at position X2
    '        + 4 bytes referring to X1 (OBSOLETE)
    '        + 4 bytes referring to X1 size (OBSOLETE)
    '        + 4 bytes referring to X2
    '        + 4 bytes referring to X2 size
    '        + 16 bytes HGLEngine.dll MD5 hash (OBSOLETE)
    '        + 16 bytes ArpsEngine.dll MD5 hash
    '        + "PACKED" string converted to Bytes using ASCII (6 bytes total)

    ''' <summary>
    ''' Used to enable or disable Log Timestamps by default
    ''' </summary>
    ''' <remarks></remarks>
    Friend Const EnableTimeStampsByDefault As Boolean = True

    ''' <summary>
    ''' Adds text to the Console Window
    ''' </summary>
    ''' <param name="text">Text to be added</param>
    ''' <param name="leaveOpen">If true, the caret will not be moved to the next line automatically after writting to the Console</param>
    ''' <param name="timestamp">If true, a Timestamp will be added to the beggining of the newly inserted line</param>
    ''' <remarks></remarks>
    Public Sub AddLog(ByVal text As String, ByVal leaveOpen As Boolean, ByVal timestamp As Boolean)
        ' Primary AddLog method, All the other ones will end calling this one
        Dim prefix As String = ""
        If timestamp = True Then
            Dim stamp As Date = Now
            Dim component As String
            component = stamp.Hour
            If component.Length = 1 Then component = "0" & component
            prefix = "[" & component & ":"
            component = stamp.Minute
            If component.Length = 1 Then component = "0" & component
            prefix &= component & "] "
        End If

        Try
            If (prefix.Length + text.Length) > (Console.BufferWidth - Console.CursorLeft) Then
                ' Text too big
                text = Left(text, Console.BufferWidth - Console.CursorLeft - 3 - prefix.Length)
                text &= "-/>"
                leaveOpen = True
            End If
        Catch ex As Exception
            ' Ignore. Uncompatible console
        End Try


        If leaveOpen = True Then
            Console.Write(prefix & text)
        Else
            Console.WriteLine(prefix & text)
        End If
    End Sub
    Public Sub AddLog(ByVal text As String, ByVal leaveOpen As Boolean)
        AddLog(text, leaveOpen, EnableTimeStampsByDefault)
    End Sub
    Public Sub AddLog(ByVal text As String)
        AddLog(text, False, EnableTimeStampsByDefault)
    End Sub
    Public Sub AddLog()
        AddLog("", False, False)
    End Sub

    ''' <summary>
    ''' Adds text to the Console Window that will be shown only if the Verbose flag is specified
    ''' </summary>
    ''' <param name="text"></param>
    ''' <remarks></remarks>
    Public Sub AddLogV(ByVal text As String)
        If Configuration.CurrentConfiguration.Verbose = True Then AddLog(text)
    End Sub

    ''' <summary>
    ''' Used to clear the Console output
    ''' </summary>
    ''' <param name="lastLine">If true, only the last line will be cleared</param>
    ''' <remarks></remarks>
    Public Sub ClearLog(ByVal lastLine As Boolean)
        If Console.CursorLeft = 0 Then
            ' At the start of the current line. Move upwards before deleting
            If Not Console.CursorTop = 0 Then Console.CursorTop -= 1
        End If

        ' Position the caret at the start of the current line and delete everything
        Console.CursorLeft = 0
        Dim currLine As Integer = Console.CursorTop
        Dim clearLine As String = StrDup(Console.BufferWidth, " ")
        Console.Write(clearLine)

        ' Reset caret position
        Console.CursorLeft = 0
        Console.CursorTop = currLine
    End Sub
    Public Sub ClearLog()
        ClearLog(False)
    End Sub

    ''' <summary>
    ''' Used to overwrite the last line on the Console window
    ''' </summary>
    ''' <param name="text">Text that will be used to overwrite the last line</param>
    ''' <param name="leaveOpen">If true, the caret will not be moved to the next line automatically after writting to the Console</param>
    ''' <param name="timestamp">If true, a Timestamp will be added to the beggining of the newly inserted line</param>
    ''' <remarks></remarks>
    Public Sub Rewrite(ByVal text As String, ByVal leaveOpen As Boolean, ByVal timestamp As Boolean)
        ClearLog(True)
        AddLog(text, leaveOpen, timestamp)
    End Sub
    Public Sub Rewrite(ByVal text As String, ByVal leaveOpen As Boolean)
        Rewrite(text, leaveOpen, EnableTimeStampsByDefault)
    End Sub
    Public Sub Rewrite(ByVal text As String)
        Rewrite(text, False, EnableTimeStampsByDefault)
    End Sub

    Sub Main()
        ' CrashHandler
        Try
            AddLog("Arphoon Package Checker", False, False)
            AddLog("By Razorback", False, False)
            AddLog("=======================================", False, False)
            AddLog()

            SecondaryMain()
        Catch ex As Exception
            AddLog()
            AddLog(" *** CRASH HANDLER TRIGGERED ***", False, False)
            AddLog("     Application has crashed", False, False)
            AddLog("  ex: " & ex.Message, False, False)
            AddLog(" loc: " & ex.Source, False, False)
            AddLog(" STACK START", False, False)
            AddLog(ex.StackTrace.ToString(), False, False)
            AddLog(" STACK END", False, False)
        End Try

        If Not Configuration.CurrentConfiguration.Unattended Then
            AddLog()
            AddLog("<press any key to exit>", False, False)
            Console.ReadKey()
        End If

        End
    End Sub

    Private Sub SecondaryMain()
        ' Initialize Configurations and Parse Command Line
        InitializeDefaultConfiguration()
        ProcessCommandLineParameters()

        If CurrentConfiguration.Standalone = True Then
            AddLog(" (Standalone executable)", False, False)
            AddLog()
        End If

        ' Pack Dlls if requested
        If Configuration.CurrentConfiguration.PackOnly Then
            AddLog()
            AddLog("   Executing DLLPacker procedure...")
            ExecutableImageOperations.Pack()
            Exit Sub
        End If

        ' Check input filename to avoid unpacking dlls unnecessarily
        If Trim(CurrentConfiguration.InputFilename) = "" Then
            AddLog("ERROR: No Input package specified. Aborted.")
            Exit Sub
        Else
            Dim fi As New IO.FileInfo(CurrentConfiguration.InputFilename)
            If Not fi.Exists Then
                AddLog("ERROR: Input package dont exists. Aborted.")
                Exit Sub
            End If
        End If

        ' Unpack Dlls is its standalone and operating normally
        ExecutableImageOperations.Unpack()

        ' Execute Arphoon Checking procedure
        Dim checker As ArphoonChecker
        checker = New ArphoonChecker(CurrentConfiguration.InputFilename)
        checker.Check()
        checker.Dispose()
        checker = Nothing
    End Sub

End Module
